/*-------------------------------------------------------------------------
 *
 * int8.c
 *	  内部 64 位整数操作
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/utils/adt/int8.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <ctype.h>
#include <limits.h>
#include <math.h>

#include "common/int.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"


typedef struct
{
	int64		current;
	int64		finish;
	int64		step;
} generate_series_fctx;


/***********************************************************************
 **
 **		64位整数的例程。
 **
 ***********************************************************************/

/*----------------------------------------------------------
 * 格式化和转换例程。
 *---------------------------------------------------------*/

/* int8in()
 */
Datum int8in(PG_FUNCTION_ARGS)
{
	char	   *fc_num = PG_GETARG_CSTRING(0);

	PG_RETURN_INT64(pg_strtoint64(fc_num));
}


/* int8out()
 */
Datum int8out(PG_FUNCTION_ARGS)
{
	int64		fc_val = PG_GETARG_INT64(0);
	char		fc_buf[MAXINT8LEN + 1];
	char	   *fc_result;
	int			fc_len;

	fc_len = pg_lltoa(fc_val, fc_buf) + 1;

	/*
	 * 由于长度已经知道，我们手动进行 palloc() 和 memcpy()
	 * 以避免 pstrdup() 中本会进行的 strlen() 调用。
	 */
	fc_result = palloc(fc_len);
	memcpy(fc_result, fc_buf, fc_len);
	PG_RETURN_CSTRING(fc_result);
}

/*
 *		int8recv			- 将外部二进制格式转换为 int8
 */
Datum int8recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);

	PG_RETURN_INT64(pq_getmsgint64(fc_buf));
}

/*
 *		int8send			- 将 int8 转换为二进制格式
 */
Datum int8send(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	StringInfoData fc_buf;

	pq_begintypsend(&fc_buf);
	pq_sendint64(&fc_buf, fc_arg1);
	PG_RETURN_BYTEA_P(pq_endtypsend(&fc_buf));
}


/*----------------------------------------------------------
 *	对于 int8 的关系运算符，包括跨数据类型比较。
 *---------------------------------------------------------*/

/* int8relop()
 * val1 是否 relop val2？
 */
Datum int8eq(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 == fc_val2);
}

Datum int8ne(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 != fc_val2);
}

Datum int8lt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 < fc_val2);
}

Datum int8gt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 > fc_val2);
}

Datum int8le(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 <= fc_val2);
}

Datum int8ge(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 >= fc_val2);
}

/* int84relop()
 * 64位 val1 是否 relop 32位 val2？
 */
Datum int84eq(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 == fc_val2);
}

Datum int84ne(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 != fc_val2);
}

Datum int84lt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 < fc_val2);
}

Datum int84gt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 > fc_val2);
}

Datum int84le(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 <= fc_val2);
}

Datum int84ge(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int32		fc_val2 = PG_GETARG_INT32(1);

	PG_RETURN_BOOL(fc_val1 >= fc_val2);
}

/* int48relop()
 * 32位 val1 是否与 64位 val2 进行比较？
 */
Datum int48eq(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 == fc_val2);
}

Datum int48ne(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 != fc_val2);
}

Datum int48lt(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 < fc_val2);
}

Datum int48gt(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 > fc_val2);
}

Datum int48le(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 <= fc_val2);
}

Datum int48ge(PG_FUNCTION_ARGS)
{
	int32		fc_val1 = PG_GETARG_INT32(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 >= fc_val2);
}

/* int82relop()
 * 64位 val1 是否与 16位 val2 进行比较？
 */
Datum int82eq(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 == fc_val2);
}

Datum int82ne(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 != fc_val2);
}

Datum int82lt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 < fc_val2);
}

Datum int82gt(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 > fc_val2);
}

Datum int82le(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 <= fc_val2);
}

Datum int82ge(PG_FUNCTION_ARGS)
{
	int64		fc_val1 = PG_GETARG_INT64(0);
	int16		fc_val2 = PG_GETARG_INT16(1);

	PG_RETURN_BOOL(fc_val1 >= fc_val2);
}

/* int28relop()
 * 16位 val1 是否与 64位 val2 进行比较？
 */
Datum int28eq(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 == fc_val2);
}

Datum int28ne(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 != fc_val2);
}

Datum int28lt(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 < fc_val2);
}

Datum int28gt(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 > fc_val2);
}

Datum int28le(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 <= fc_val2);
}

Datum int28ge(PG_FUNCTION_ARGS)
{
	int16		fc_val1 = PG_GETARG_INT16(0);
	int64		fc_val2 = PG_GETARG_INT64(1);

	PG_RETURN_BOOL(fc_val1 >= fc_val2);
}

/*
 * in_range 支持函数用于 int8。
 *
 * 注意：我们不需要提供 int8_int4 或 int8_int2 的变体，因为偏移值的隐式
 * 转换已妥善处理这些情况。
 */
Datum in_range_int8_int8(PG_FUNCTION_ARGS)
{
	int64		fc_val = PG_GETARG_INT64(0);
	int64		fc_base = PG_GETARG_INT64(1);
	int64		fc_offset = PG_GETARG_INT64(2);
	bool		fc_sub = PG_GETARG_BOOL(3);
	bool		fc_less = PG_GETARG_BOOL(4);
	int64		fc_sum;

	if (fc_offset < 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
				 errmsg("invalid preceding or following size in window function")));

	if (fc_sub)
		fc_offset = -fc_offset;		/* 不能溢出 */

	if (unlikely(pg_add_s64_overflow(fc_base, fc_offset, &fc_sum)))
	{
		/*
		 * 如果 sub 为 false，真实的和肯定大于 val，因此正确
		 * 的答案与 "less" 相同。如果 sub 为 true，真实的和
		 * 肯定小于 val，因此答案为 "!less"。
		 */
		PG_RETURN_BOOL(fc_sub ? !fc_less : fc_less);
	}

	if (fc_less)
		PG_RETURN_BOOL(fc_val <= fc_sum);
	else
		PG_RETURN_BOOL(fc_val >= fc_sum);
}


/*----------------------------------------------------------
 * 64位整数的算术运算符。
 *---------------------------------------------------------*/

Datum int8um(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);
	int64		fc_result;

	if (unlikely(fc_arg == PG_INT64_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	fc_result = -fc_arg;
	PG_RETURN_INT64(fc_result);
}

Datum int8up(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);

	PG_RETURN_INT64(fc_arg);
}

Datum int8pl(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_add_s64_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int8mi(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_sub_s64_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int8mul(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_mul_s64_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int8div(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (fc_arg2 == 0)
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * INT64_MIN / -1 是个问题，因为结果无法在
	 * 一个二进制补码机器中表示。某些机器产生 INT64_MIN，有些
	 * 产生零，有些抛出异常。我们可以通过识别 -1 的除法与取反相同来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT64_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT64(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT64(fc_result);
}

/* int8abs()
 * 绝对值
 */
Datum int8abs(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_result;

	if (unlikely(fc_arg1 == PG_INT64_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	fc_result = (fc_arg1 < 0) ? -fc_arg1 : fc_arg1;
	PG_RETURN_INT64(fc_result);
}

/* int8mod()
 * 模运算。
 */
Datum int8mod(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * 某些机器对 INT64_MIN % -1 抛出浮点异常，
	 * 这有点愚蠢，因为正确的答案是完美
	 * 定义的，即零。
	 */
	if (fc_arg2 == -1)
		PG_RETURN_INT64(0);

	/* 不可能溢出 */

	PG_RETURN_INT64(fc_arg1 % fc_arg2);
}

/*
 * 最大公约数
 *
 * 返回恰好整除两个输入的最大的正整数。
 * 特殊情况：
 *   - gcd(x, 0) = gcd(0, x) = abs(x)
 *   		因为 0 能被任何数整除
 *   - gcd(0, 0) = 0
 *   		符合之前的定义，并且是一个常见的约定
 *
 * 如果任一输入为 INT64_MIN，必须特别小心 ---
 * gcd(0, INT64_MIN)、gcd(INT64_MIN, 0) 和 gcd(INT64_MIN, INT64_MIN) 
 * 均等于 abs(INT64_MIN)，而这在64位有符号整数中无法表示。
 */
static int64 fc_int8gcd_internal(int64 fc_arg1, int64 fc_arg2)
{
	int64		fc_swap;
	int64		fc_a1,
				fc_a2;

	/*
	 * 将更大的绝对值放入 arg1。
	 *
	 * 这将自动发生在下面的循环中，但避免了一个
	 * 昂贵的模运算，并简化了下面对 INT64_MIN 的特殊情况处理。
	 *
	 * 我们在负数范围内执行此操作以处理 INT64_MIN。
	 */
	fc_a1 = (fc_arg1 < 0) ? fc_arg1 : -fc_arg1;
	fc_a2 = (fc_arg2 < 0) ? fc_arg2 : -fc_arg2;
	if (fc_a1 > fc_a2)
	{
		fc_swap = fc_arg1;
		fc_arg1 = fc_arg2;
		fc_arg2 = fc_swap;
	}

	/* 处理 INT64_MIN 时需要特别小心。见上面的评论。 */
	if (fc_arg1 == PG_INT64_MIN)
	{
		if (fc_arg2 == 0 || fc_arg2 == PG_INT64_MIN)
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));

		/*
		 * 某些机器对 INT64_MIN % -1 抛出浮点异常，
		 * 这有点愚蠢，因为正确的答案是完美
		 * 定义的，即零。对此进行防范，只需返回
		 * 结果，gcd(INT64_MIN, -1) = 1。
		 */
		if (fc_arg2 == -1)
			return 1;
	}

	/* 使用欧几里得算法找到 GCD */
	while (fc_arg2 != 0)
	{
		fc_swap = fc_arg2;
		fc_arg2 = fc_arg1 % fc_arg2;
		fc_arg1 = fc_swap;
	}

	/*
	 * 确保结果为正。（我们知道再也没有 INT64_MIN）。
	 */
	if (fc_arg1 < 0)
		fc_arg1 = -fc_arg1;

	return fc_arg1;
}

Datum int8gcd(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	fc_result = fc_int8gcd_internal(fc_arg1, fc_arg2);

	PG_RETURN_INT64(fc_result);
}

/*
 * 最小公倍数
 */
Datum int8lcm(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_gcd;
	int64		fc_result;

	/*
	 * 处理 lcm(x, 0) = lcm(0, x) = 0 作为特殊情况。这防止了
	 * 当 x 为零时的除零错误，以及当 x = INT64_MIN 时
	 * 由于 GCD 计算而导致的溢出错误。
	 */
	if (fc_arg1 == 0 || fc_arg2 == 0)
		PG_RETURN_INT64(0);

	/* lcm(x, y) = abs(x / gcd(x, y) * y) */
	fc_gcd = fc_int8gcd_internal(fc_arg1, fc_arg2);
	fc_arg1 = fc_arg1 / fc_gcd;

	if (unlikely(pg_mul_s64_overflow(fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));

	/* 如果结果是 INT64_MIN，则无法表示。 */
	if (unlikely(fc_result == PG_INT64_MIN))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));

	if (fc_result < 0)
		fc_result = -fc_result;

	PG_RETURN_INT64(fc_result);
}

Datum int8inc(PG_FUNCTION_ARGS)
{
	/*
	 * 当 int8 以引用方式传递时，我们提供此特殊情况以避免
	 * COUNT() 的 palloc 开销：当作为聚合调用时，我们知道
	 * 参数是可修改的本地存储，因此只需就地更新它。
	 * （如果 int8 以值传递，当然这既无用又不正确，所以仅仅是进行条件编译。）
	 */
#ifndef USE_FLOAT8_BYVAL		/* 也控制 int8 */
	if (AggCheckCallContext(fcinfo, NULL))
	{
		int64	   *fc_arg = (int64 *) PG_GETARG_POINTER(0);

		if (unlikely(pg_add_s64_overflow(*fc_arg, 1, fc_arg)))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));

		PG_RETURN_POINTER(fc_arg);
	}
	else
#endif
	{
		/* 不是作为聚合调用，因此就以笨方式处理它 */
		int64		fc_arg = PG_GETARG_INT64(0);
		int64		fc_result;

		if (unlikely(pg_add_s64_overflow(fc_arg, 1, &fc_result)))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));

		PG_RETURN_INT64(fc_result);
	}
}

Datum int8dec(PG_FUNCTION_ARGS)
{
	/*
	 * 当 int8 以引用方式传递时，我们提供此特殊情况以避免
	 * COUNT() 的 palloc 开销：当作为聚合调用时，我们知道
	 * 参数是可修改的本地存储，因此只需就地更新它。
	 * （如果 int8 以值传递，当然这既无用又不正确，所以仅仅是进行条件编译。）
	 */
#ifndef USE_FLOAT8_BYVAL		/* 也控制 int8 */
	if (AggCheckCallContext(fcinfo, NULL))
	{
		int64	   *fc_arg = (int64 *) PG_GETARG_POINTER(0);

		if (unlikely(pg_sub_s64_overflow(*fc_arg, 1, fc_arg)))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));
		PG_RETURN_POINTER(fc_arg);
	}
	else
#endif
	{
		/* 不是作为聚合调用，因此就以笨方式处理它 */
		int64		fc_arg = PG_GETARG_INT64(0);
		int64		fc_result;

		if (unlikely(pg_sub_s64_overflow(fc_arg, 1, &fc_result)))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));

		PG_RETURN_INT64(fc_result);
	}
}


/*
 * 这些函数与 int8inc/int8dec 完全相同，但用于
 * 仅计算非空值的聚合。由于这些函数被声明为严格，
 * 在我们到达这里之前，null 检查已经发生，我们
 * 所需的只是增加状态值。我们实际上可以使这些 pg_proc 
 * 条目直接指向 int8inc/int8dec，但那样的话，opr_sanity 回归
 * 测试将对内置函数的不匹配条目提出抱怨。
 */

Datum int8inc_any(PG_FUNCTION_ARGS)
{
	return int8inc(fcinfo);
}

Datum int8inc_float8_float8(PG_FUNCTION_ARGS)
{
	return int8inc(fcinfo);
}

Datum int8dec_any(PG_FUNCTION_ARGS)
{
	return int8dec(fcinfo);
}

/*
 * int8inc_support
 *		int8inc() 和 int8inc_any() 的支持函数
 */
Datum int8inc_support(PG_FUNCTION_ARGS)
{
	Node	   *fc_rawreq = (Node *) PG_GETARG_POINTER(0);

	if (IsA(fc_rawreq, SupportRequestWFuncMonotonic))
	{
		SupportRequestWFuncMonotonic *fc_req = (SupportRequestWFuncMonotonic *) fc_rawreq;
		MonotonicFunction fc_monotonic = MONOTONICFUNC_NONE;
		int			fc_frameOptions = fc_req->window_clause->frameOptions;
		WindowFunc *fc_wfunc = fc_req->window_func;

		if (list_length(fc_wfunc->args) == 1)
		{
			Node *fc_expr = eval_const_expressions(NULL, linitial(fc_wfunc->args));

			/*
			 * 由于 v17 之前版本 WindowClause runConditions 的节点表示，
			 * 我们需要坚持 count 参数是 Const，以允许安全应用
			 * runCondition 优化。
			 */
			if (!IsA(fc_expr, Const))
				PG_RETURN_POINTER(NULL);
		}

		/* 如果没有 ORDER BY 子句，则所有行都是同级 */
		if (fc_req->window_clause->orderClause == NIL)
			fc_monotonic = MONOTONICFUNC_BOTH;
		else
		{
			/*
			 * 否则，要考虑框架选项。当框架边界是窗口的起始位置时，
			 * 结果值永远不会减少，因此是单调递增的。
			 */
			if (fc_frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
				fc_monotonic |= MONOTONICFUNC_INCREASING;

			/*
			 * 同样，如果框架边界是窗口的结束位置，结果值也永远不会减少。
			 */
			if (fc_frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
				fc_monotonic |= MONOTONICFUNC_DECREASING;
		}

		fc_req->monotonic = fc_monotonic;
		PG_RETURN_POINTER(fc_req);
	}

	PG_RETURN_POINTER(NULL);
}


Datum int8larger(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	fc_result = ((fc_arg1 > fc_arg2) ? fc_arg1 : fc_arg2);

	PG_RETURN_INT64(fc_result);
}

Datum int8smaller(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	fc_result = ((fc_arg1 < fc_arg2) ? fc_arg1 : fc_arg2);

	PG_RETURN_INT64(fc_result);
}

Datum int84pl(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int64		fc_result;

	if (unlikely(pg_add_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int84mi(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int64		fc_result;

	if (unlikely(pg_sub_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int84mul(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int64		fc_result;

	if (unlikely(pg_mul_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int84div(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);
	int64		fc_result;

	if (fc_arg2 == 0)
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * INT64_MIN / -1 是个问题，因为结果无法在
	 * 一个二进制补码机器中表示。某些机器产生 INT64_MIN，有些
	 * 产生零，有些抛出异常。我们可以通过识别 -1 的除法与取反相同来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT64_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT64(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT64(fc_result);
}

Datum int48pl(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_add_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int48mi(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_sub_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int48mul(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_mul_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int48div(PG_FUNCTION_ARGS)
{
	int32		fc_arg1 = PG_GETARG_INT32(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/* 不可能溢出 */
	PG_RETURN_INT64((int64) fc_arg1 / fc_arg2);
}

Datum int82pl(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int64		fc_result;

	if (unlikely(pg_add_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int82mi(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int64		fc_result;

	if (unlikely(pg_sub_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int82mul(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int64		fc_result;

	if (unlikely(pg_mul_s64_overflow(fc_arg1, (int64) fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int82div(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int16		fc_arg2 = PG_GETARG_INT16(1);
	int64		fc_result;

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/*
	 * INT64_MIN / -1 是个问题，因为结果无法在
	 * 一个二进制补码机器中表示。某些机器产生 INT64_MIN，有些
	 * 产生零，有些抛出异常。我们可以通过识别 -1 的除法与取反相同来规避这个问题。
	 */
	if (fc_arg2 == -1)
	{
		if (unlikely(fc_arg1 == PG_INT64_MIN))
			ereport(ERROR,
					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
					 errmsg("bigint out of range")));
		fc_result = -fc_arg1;
		PG_RETURN_INT64(fc_result);
	}

	/* 不可能溢出 */

	fc_result = fc_arg1 / fc_arg2;

	PG_RETURN_INT64(fc_result);
}

Datum int28pl(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_add_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int28mi(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_sub_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int28mul(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);
	int64		fc_result;

	if (unlikely(pg_mul_s64_overflow((int64) fc_arg1, fc_arg2, &fc_result)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));
	PG_RETURN_INT64(fc_result);
}

Datum int28div(PG_FUNCTION_ARGS)
{
	int16		fc_arg1 = PG_GETARG_INT16(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	if (unlikely(fc_arg2 == 0))
	{
		ereport(ERROR,
				(errcode(ERRCODE_DIVISION_BY_ZERO),
				 errmsg("division by zero")));
		/* 确保编译器意识到我们不能到达除法 (gcc bug) */
		PG_RETURN_NULL();
	}

	/* 不可能溢出 */
	PG_RETURN_INT64((int64) fc_arg1 / fc_arg2);
}

/* 二进制算术
 *
 *		int8and		- 返回 arg1 & arg2
 *		int8or		- 返回 arg1 | arg2
 *		int8xor		- 返回 arg1 # arg2
 *		int8not		- 返回 ~arg1
 *		int8shl		- 返回 arg1 << arg2
 *		int8shr		- 返回 arg1 >> arg2
 */

Datum int8and(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	PG_RETURN_INT64(fc_arg1 & fc_arg2);
}

Datum int8or(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	PG_RETURN_INT64(fc_arg1 | fc_arg2);
}

Datum int8xor(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int64		fc_arg2 = PG_GETARG_INT64(1);

	PG_RETURN_INT64(fc_arg1 ^ fc_arg2);
}

Datum int8not(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);

	PG_RETURN_INT64(~fc_arg1);
}

Datum int8shl(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT64(fc_arg1 << fc_arg2);
}

Datum int8shr(PG_FUNCTION_ARGS)
{
	int64		fc_arg1 = PG_GETARG_INT64(0);
	int32		fc_arg2 = PG_GETARG_INT32(1);

	PG_RETURN_INT64(fc_arg1 >> fc_arg2);
}

/*----------------------------------------------------------
 *	转换操作符。
 *---------------------------------------------------------*/

Datum int48(PG_FUNCTION_ARGS)
{
	int32		fc_arg = PG_GETARG_INT32(0);

	PG_RETURN_INT64((int64) fc_arg);
}

Datum int84(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);

	if (unlikely(fc_arg < PG_INT32_MIN) || unlikely(fc_arg > PG_INT32_MAX))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("integer out of range")));

	PG_RETURN_INT32((int32) fc_arg);
}

Datum int28(PG_FUNCTION_ARGS)
{
	int16		fc_arg = PG_GETARG_INT16(0);

	PG_RETURN_INT64((int64) fc_arg);
}

Datum int82(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);

	if (unlikely(fc_arg < PG_INT16_MIN) || unlikely(fc_arg > PG_INT16_MAX))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("smallint out of range")));

	PG_RETURN_INT16((int16) fc_arg);
}

Datum i8tod(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);
	float8		fc_result;

	fc_result = fc_arg;

	PG_RETURN_FLOAT8(fc_result);
}

/* dtoi8()
 * 将 float8 转换为 8 字节整数。
 */
Datum dtoi8(PG_FUNCTION_ARGS)
{
	float8		fc_num = PG_GETARG_FLOAT8(0);

	/*
	 * 去掉输入中的任何小数部分。这是为了避免在将要四舍五入
	 * 到范围中的值时出错。注意假设rint()将会将NaN或Inf原封不动地传递。
	 */
	fc_num = rint(fc_num);

	/* 范围检查 */
	if (unlikely(isnan(fc_num) || !FLOAT8_FITS_IN_INT64(fc_num)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));

	PG_RETURN_INT64((int64) fc_num);
}

Datum i8tof(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);
	float4		fc_result;

	fc_result = fc_arg;

	PG_RETURN_FLOAT4(fc_result);
}

/* ftoi8()
 * 将 float4 转换为 8 字节整数。
 */
Datum ftoi8(PG_FUNCTION_ARGS)
{
	float4		fc_num = PG_GETARG_FLOAT4(0);

	/*
	 * 去掉输入中的任何小数部分。这是为了避免在将要四舍五入
	 * 到范围中的值时出错。注意假设rint()将会将NaN或Inf原封不动地传递。
	 */
	fc_num = rint(fc_num);

	/* 范围检查 */
	if (unlikely(isnan(fc_num) || !FLOAT4_FITS_IN_INT64(fc_num)))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("bigint out of range")));

	PG_RETURN_INT64((int64) fc_num);
}

Datum i8tooid(PG_FUNCTION_ARGS)
{
	int64		fc_arg = PG_GETARG_INT64(0);

	if (unlikely(fc_arg < 0) || unlikely(fc_arg > PG_UINT32_MAX))
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("OID out of range")));

	PG_RETURN_OID((Oid) fc_arg);
}

Datum oidtoi8(PG_FUNCTION_ARGS)
{
	Oid			fc_arg = PG_GETARG_OID(0);

	PG_RETURN_INT64((int64) fc_arg);
}

/*
 * 非持久数字序列生成器
 */
Datum generate_series_int8(PG_FUNCTION_ARGS)
{
	return generate_series_step_int8(fcinfo);
}

Datum generate_series_step_int8(PG_FUNCTION_ARGS)
{
	FuncCallContext *fc_funcctx;
	generate_series_fctx *fc_fctx;
	int64		fc_result;
	MemoryContext fc_oldcontext;

	/* 仅在函数的第一次调用时完成的工作 */
	if (SRF_IS_FIRSTCALL())
	{
		int64		fc_start = PG_GETARG_INT64(0);
		int64		fc_finish = PG_GETARG_INT64(1);
		int64		fc_step = 1;

		/* 检查我们是否被提供了显式步长 */
		if (PG_NARGS() == 3)
			fc_step = PG_GETARG_INT64(2);
		if (fc_step == 0)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("step size cannot equal zero")));

		/* 为跨调用持久性创建一个函数上下文 */
		fc_funcctx = SRF_FIRSTCALL_INIT();

		/*
		 * 切换到适合多次函数调用的内存上下文
		 */
		fc_oldcontext = MemoryContextSwitchTo(fc_funcctx->multi_call_memory_ctx);

		/* 为用户上下文分配内存 */
		fc_fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));

		/*
		 * 使用 fctx 在调用之间保持状态。用原始起始值初始化当前值
		 */
		fc_fctx->current = fc_start;
		fc_fctx->finish = fc_finish;
		fc_fctx->step = fc_step;

		fc_funcctx->user_fctx = fc_fctx;
		MemoryContextSwitchTo(fc_oldcontext);
	}

	/* 每次调用函数时完成的工作 */
	fc_funcctx = SRF_PERCALL_SETUP();

	/*
	 * 获取保存的状态，并将当前值作为本次迭代的结果
	 */
	fc_fctx = fc_funcctx->user_fctx;
	fc_result = fc_fctx->current;

	if ((fc_fctx->step > 0 && fc_fctx->current <= fc_fctx->finish) ||
		(fc_fctx->step < 0 && fc_fctx->current >= fc_fctx->finish))
	{
		/*
		 * 在为下一次迭代做准备时递增当前值。如果下一个值的
		 * 计算溢出，则这是最终结果。
		 */
		if (pg_add_s64_overflow(fc_fctx->current, fc_fctx->step, &fc_fctx->current))
			fc_fctx->step = 0;

		/* 当还有更多内容要发送时执行 */
		SRF_RETURN_NEXT(fc_funcctx, Int64GetDatum(fc_result));
	}
	else
		/* 当没有更多内容时执行 */
		SRF_RETURN_DONE(fc_funcctx);
}

/*
 * 生成序列 (int8, int8 [, int8]) 的计划支持函数
 */
Datum generate_series_int8_support(PG_FUNCTION_ARGS)
{
	Node	   *fc_rawreq = (Node *) PG_GETARG_POINTER(0);
	Node	   *fc_ret = NULL;

	if (IsA(fc_rawreq, SupportRequestRows))
	{
		/* 尝试估算返回的行数 */
		SupportRequestRows *fc_req = (SupportRequestRows *) fc_rawreq;

		if (is_funcclause(fc_req->node))	/* 过于谨慎 */
		{
			List	   *fc_args = ((FuncExpr *) fc_req->node)->args;
			Node	   *fc_arg1,
					   *fc_arg2,
					   *fc_arg3;

			/* 在这里我们可以使用估计的参数值 */
			fc_arg1 = estimate_expression_value(fc_req->root, linitial(fc_args));
			fc_arg2 = estimate_expression_value(fc_req->root, lsecond(fc_args));
			if (list_length(fc_args) >= 3)
				fc_arg3 = estimate_expression_value(fc_req->root, lthird(fc_args));
			else
				fc_arg3 = NULL;

			/*
			 * 如果任何参数是常量 NULL，我们可以安全地假设返回零行。
			 * 否则，如果它们都是非 NULL 常量，我们可以计算将返回的行数。
			 * 使用双精度算术来避免溢出风险。
			 */
			if ((IsA(fc_arg1, Const) &&
				 ((Const *) fc_arg1)->constisnull) ||
				(IsA(fc_arg2, Const) &&
				 ((Const *) fc_arg2)->constisnull) ||
				(fc_arg3 != NULL && IsA(fc_arg3, Const) &&
				 ((Const *) fc_arg3)->constisnull))
			{
				fc_req->rows = 0;
				fc_ret = (Node *) fc_req;
			}
			else if (IsA(fc_arg1, Const) &&
					 IsA(fc_arg2, Const) &&
					 (fc_arg3 == NULL || IsA(fc_arg3, Const)))
			{
				double		fc_start,
							fc_finish,
							fc_step;

				fc_start = DatumGetInt64(((Const *) fc_arg1)->constvalue);
				fc_finish = DatumGetInt64(((Const *) fc_arg2)->constvalue);
				fc_step = fc_arg3 ? DatumGetInt64(((Const *) fc_arg3)->constvalue) : 1;

				/* 这个方程适用于步长的任意符号 */
				if (fc_step != 0)
				{
					fc_req->rows = floor((fc_finish - fc_start + fc_step) / fc_step);
					fc_ret = (Node *) fc_req;
				}
			}
		}
	}

	PG_RETURN_POINTER(fc_ret);
}
